home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_13_02 / cepek / flashtst.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-26  |  13.4 KB  |  520 lines

  1. /* flashtst.c - flash memory utility routines test module */
  2.  
  3. /*** THIS MODULE IS PROVIDED BEING PROVIDED ON THE C/C++ USER'S
  4.         JOURNAL CODE DISK AS SAMPLE CODE ONLY -- IT WON'T COMPILE
  5.         FOR YOU WITHOUT SOME CUSTOMIZING FOR YOUR IMPLEMENTATION ***/
  6.  
  7. /***
  8. This module contains routines which test the routines in fmutl.c.
  9.  
  10. fm_intro() performs some nice "start-up" stuff for utilities.
  11.  
  12. fm_short_test() is a quick but destructive test, suitable for
  13. manufacturing to run when checking out a newly built unit.
  14.  
  15. This module can optionally be built to include a "huge test" routine
  16. for algorithm confidence testing.
  17.  
  18. This module can also optionally be built as a stand-alone utility which
  19. performs either the short or huge tests.
  20.  
  21. NOTE:  Each time flash memories are reprogrammed they slow down a
  22. little (erases and writes take longer).  Thus, these tests should not
  23. be executed repeatedly, since the performance and useful life of the
  24. devices decreases with each test cycle.
  25.  
  26. ***/
  27.  
  28.  
  29. #ifndef STANDALONE        /* (allows this to be set on compile cmd) */
  30. #define STANDALONE    0    /* non-zero for FLASHTST utility */
  31. #endif
  32.  
  33. #ifndef HUGE_TEST        /* (allows this to be set on compile cmd) */
  34. #define    HUGE_TEST    1    /* non-zero for Huge test version */
  35. #endif
  36.  
  37.  
  38. #include <string.h>
  39. #include "sword.h"
  40. #include "keyutl.h"
  41. #include "fmutl.h"
  42.  
  43. extern long fm_tot_errs;    /* in fmerrmsg.c */
  44.  
  45. extern char FreeRAM[];        /* in freeram.s68 */
  46.  
  47.  
  48.  
  49. /*****************************************************************************
  50. Delay for the indicated amount of time while checking for switches.
  51. Returns 0 if no switches pressed; set bits indicate switches pressed.
  52. *****************************************************************************/
  53.  
  54. static unsigned char SwiDelay(delay)
  55. int delay;
  56. {
  57.     unsigned char SwiState;
  58.  
  59.     SwiState = 0;
  60.     while (delay > 0)
  61.     {
  62.         SwiState |= (~(SWITCH)) & 0x0f;
  63.         Delay(10);
  64.         delay -= 10;
  65.     }
  66.     return SwiState;
  67. }
  68.  
  69.  
  70.  
  71. /*****************************************************************************
  72. Handle an error.
  73. *****************************************************************************/
  74.  
  75. static void Err(c)
  76. char c;
  77. {
  78.     fm_err_msg(c, 300, 9000);
  79. }
  80.  
  81.  
  82.  
  83. /*****************************************************************************
  84. Reset chips, display device type and total size found; returns non-zero if
  85. any switches were used.  The FMINFO structure is filled with data from an
  86. fm_status() call.
  87. *****************************************************************************/
  88.  
  89. fm_intro(pFlash, pFMInfo, errchr, delay)
  90. unsigned short *pFlash;        /* ptr to base of Flash Memory space */
  91. FMINFO *pFMInfo;        /* ptr to structure to fill with flash data */
  92. char errchr;            /* chr to use for errmsg display */
  93. int delay;            /* msec to pause for caller's greeting display */
  94. {
  95.     unsigned char Switches;
  96.  
  97.     /* this delay is to pause for the caller's greeting display: */
  98.     Switches = SwiDelay(delay);
  99.  
  100.     /* reset chips and get info about them: */
  101.     DspText("Reset...", 1, 0, 40);
  102.     Switches |= SwiDelay(200);
  103.     if (!fm_status(pFlash, pFMInfo))
  104.         Err(errchr);
  105.     DspText("Done", 1, 12, 4);
  106.     Switches |= SwiDelay(1000);
  107.  
  108.     /* display mfr/device name string: */
  109.     DspText("(2)", 1, 0, 40);
  110.     DspText(pFMInfo->pDevName, 1, 4, 36);
  111.     Switches |= SwiDelay(1500);
  112.  
  113.     /* display amount of flash found: */
  114.     if (pFMInfo->TotalSize >= 1024*1024)
  115.     {    DspNum(pFMInfo->TotalSize / (1024*1024), 1, 0, 4);
  116.         DspText("Mbytes total", 1, 4, 13);
  117.     }
  118.     else
  119.     {    DspNum(pFMInfo->TotalSize / 1024, 1, 0, 4);
  120.         DspText("Kbytes total", 1, 4, 13);
  121.     }
  122.     Switches |= SwiDelay(2500);
  123.  
  124.     /* return switch status (0 = none pressed): */
  125.     return Switches;
  126. }
  127.  
  128.  
  129.  
  130. /*****************************************************************************
  131. Short flash memory test routine.  THIS IS A DESTRUCTIVE TEST.  The
  132. contents of flash memory contents are erased and rewritten 3 times.
  133. If the caller zeros the fm_tot_errs global before calling this routine,
  134. then fm_tot_errs can be used to check for errors.
  135. *****************************************************************************/
  136.  
  137. void fm_short_test(pFlash, pFMInfo, pScratch)
  138. unsigned short *pFlash;        /* ptr to base of Flash Memory space */
  139. FMINFO *pFMInfo;        /* ptr to structure containing flash data */
  140. unsigned short *pScratch;    /* ptr to buffer of pFMInfo->TotalSize bytes */
  141. {
  142.     register volatile unsigned short *ptr, *ptr2, *pRam;
  143.     register unsigned short act;
  144.     register unsigned long randval, rval1, rval2;
  145.  
  146. #if 0    /* just do one sector, for debugging/timing tests: */
  147.     pFMInfo->TotalSize /= pFMInfo->NumSect_;
  148. #endif
  149.  
  150.     /* TEST #1: write zeros to all of flash memory: */
  151.     DspText("#1: Writing 0s", 1, 0, 40);
  152.     memset(pScratch, 0, pFMInfo->TotalSize);
  153.     DspText("#1: Writing 0s...", 1, 0, 40);
  154.     if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
  155.         Err('1');
  156.  
  157.     /* verify all zeros: */
  158.     DspText("#1: Verifying...", 1, 0, 40);
  159.     pRam = pScratch;
  160.     ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
  161.     for (ptr = pFlash;  ptr < ptr2;  ++ptr)
  162.     {    act = *ptr;
  163.         if (*pRam != act)
  164.         {    fm_error(ptr, *pRam, act, 0xE1);
  165.             Err('1');
  166.         }
  167.     }
  168.  
  169.  
  170.     /* TEST #2: write ones to all of flash memory: */
  171.     DspText("#2: Writing 1s", 1, 0, 40);
  172.     memset(pScratch, 0xff, pFMInfo->TotalSize);
  173.     DspText("#2: Writing 1s...", 1, 0, 40);
  174.     if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
  175.         Err('2');
  176.  
  177.     /* verify all ones: */
  178.     DspText("#2: Verifying...", 1, 0, 40);
  179.     pRam = pScratch;
  180.     ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
  181.     for (ptr = pFlash;  ptr < ptr2;  ++ptr)
  182.     {    act = *ptr;
  183.         if (*pRam != act)
  184.         {    fm_error(ptr, *pRam, act, 0xE2);
  185.             Err('2');
  186.         }
  187.     }
  188.  
  189.  
  190.     /* TEST 3: write rotating ones and zeros pattern (once): */
  191.     DspText("#3: Rot 0s&1s", 1, 0, 40);
  192.  
  193.     /* fill first 17 slots with nice rotating numbers (and an all 1's): */
  194.     ptr = pScratch;
  195.     *ptr++ = 0xfe01;
  196.     *ptr++ = 0xfd02;
  197.     *ptr++ = 0xfb04;
  198.     *ptr++ = 0xf708;
  199.     *ptr++ = 0xef10;
  200.     *ptr++ = 0xdf20;
  201.     *ptr++ = 0xbf40;
  202.     *ptr++ = 0x7f80;
  203.     *ptr++ = 0xffff;
  204.     for (act = 8;  act;  --act)
  205.     {    *ptr = *(ptr - 9) ^ 0xffff;
  206.         ++ptr;
  207.     }
  208.  
  209.     /* now duplicate this through the rest of our RAM buffer: */
  210.     pRam = pScratch;
  211.     ptr2 = pRam + (pFMInfo->TotalSize >> 1);
  212.     while (ptr < ptr2)
  213.         *ptr++ = *pRam++;
  214.  
  215.     /* write it out: */
  216.     DspText("#3: Rot 0s&1s...", 1, 0, 40);
  217.     if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
  218.         Err('3');
  219.  
  220.     /* verify the values: */
  221.     DspText("#3: Verifying...", 1, 0, 40);
  222.     pRam = pScratch;
  223.     ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
  224.     for (ptr = pFlash;  ptr < ptr2;  ++ptr)
  225.     {    act = *ptr;
  226.         if (*pRam++ != act)
  227.         {    fm_error(ptr, pRam[-1], act, 0xE3);
  228.             Err('3');
  229.         }
  230.     }
  231.  
  232.  
  233.     /* TEST #4: write, then read, random values: */
  234.     DspText("#4: Unique data", 1, 0, 40);
  235.     randval = 0;  /* seed */
  236.  
  237.     /* fill RAM buffer with random values: */
  238.     /* (random # fn is from The Standard C Library by P.J.Plauger, p359) */
  239.     rval1 = 1103515245;
  240.     rval2 = 12345;
  241.     ptr2 = pScratch + (pFMInfo->TotalSize >> 1);
  242.     for (ptr = pScratch;  ptr < ptr2;  ++ptr)
  243.     {    randval = randval * rval1 + rval2;
  244.         *ptr = (unsigned short) (randval >> 16);
  245.     }
  246.  
  247.     /* write it out: */
  248.     DspText("#4: Unique data...", 1, 0, 40);
  249.     if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
  250.         Err('4');
  251.  
  252.     /* verify the values: */
  253.     DspText("#4: Verifying...", 1, 0, 40);
  254.     pRam = pScratch;
  255.     ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
  256.     for (ptr = pFlash;  ptr < ptr2;  ++ptr)
  257.     {    act = *ptr;
  258.         if (*pRam++ != act)
  259.         {    fm_error(ptr, pRam[-1], act, 0xE4);
  260.             Err('4');
  261.         }
  262.     }
  263.  
  264.  
  265.     DspText("Done", 1, 0, 40);
  266.     Delay(500);
  267. }
  268.  
  269.  
  270.  
  271. #if HUGE_TEST
  272.  
  273.  
  274. /* (random # fn is from The Standard C Library by P.J.Plauger, p359) */
  275. #define    RND1(x)  ((x) * 1103515245 + 12345)
  276. #define    RND2(x)  ((x) >> 16)
  277. static unsigned long randval = 0;
  278.  
  279.  
  280. /*****************************************************************************
  281. Return a random value in the range [2,mask-1].  Mask should have lots of
  282. low bits set.
  283. *****************************************************************************/
  284.  
  285. static unsigned RndOfs(mask)
  286. {
  287.     unsigned offset;
  288.  
  289.     do
  290.     {    randval = RND1(randval);
  291.         offset = RND2(randval) & mask;
  292.     } while (offset == 0  ||  offset == 1  ||  offset == mask);
  293.  
  294.     return offset;
  295. }
  296.  
  297.  
  298.  
  299. #define    FM_ERASE_VAL    0xFFFF        /* value of an erased location */
  300.  
  301.  
  302. /*****************************************************************************
  303. Huge flash memory test.  An exhaustive battery of sector boundary
  304. write tests.  THIS IS A DESTRUCTIVE TEST -- flash memory contents are
  305. erased.  Rigorous boundary tests are performed using the fm_write()
  306. routine.
  307.  
  308. This test runs 528 erase/write/verify cycles, checking all combinations
  309. of fm_write calls with varying start and end sector boundary conditions:
  310.     - at the sector boundary
  311.     - one word past the sector boundary
  312.     - one word prior to the next sector boundary
  313.     - one other random position within the sector
  314.  
  315. This test takes about two hours to run.  A running error total is shown on
  316. the display; error specifics are output using printf() calls.
  317. *****************************************************************************/
  318.  
  319. void fm_huge_test(pBase, pFMInfo, pScratch)
  320. unsigned short *pBase;        /* ptr to base of Flash Memory space */
  321. FMINFO *pFMInfo;        /* ptr to filled in structure */
  322. unsigned short *pScratch;    /* ptr to scratch sector storage area */
  323. {
  324.     volatile unsigned short *ptr;
  325.     unsigned short *pStart, *pEnd, *pScr0;        /* pEnd is exclusive */
  326.     unsigned short act, exp;
  327.     int hi, lo, tstnum;
  328.  
  329.     /* carve out a section of scratch area for sector buffer: */
  330.     pScr0 = pScratch;
  331.     pScratch += (pFMInfo->SectorSize >> 1);
  332.  
  333.     /* init display and some other stuff: */
  334.     tstnum = 0;
  335.     DspText("  0/528  no errs", 1, 0, 16);
  336.     randval = 0;  /* seed */
  337.  
  338.     /* outer loop: */
  339.     for (lo = 0;  lo <= 31;  ++lo)
  340.     {
  341.         /* inner loop: */
  342.         for (hi = lo + 1;  hi <= 32;  ++hi)
  343.         {
  344.             /* construct pStart pointer: */
  345.             pStart = pBase + (lo / 4) * (pFMInfo->SectorSize >> 1);
  346.             switch (lo & 3)
  347.             {
  348.                 case 1: pStart += 1;  break;
  349.                 case 2: pStart += RndOfs((pFMInfo->SectorSize >> 1) - 1);
  350.                     break;
  351.                 case 3:    pStart += (pFMInfo->SectorSize >> 1) - 1;
  352.             }
  353.  
  354.             /* construct pEnd pointer: */
  355.             pEnd = pBase + (hi / 4) * (pFMInfo->SectorSize >> 1);
  356.             switch (hi & 3)
  357.             {
  358.                 case 1: pEnd += 1;  break;
  359.                 case 2: pEnd += RndOfs((pFMInfo->SectorSize >> 1) - 1);
  360.                     break;
  361.                 case 3:    pEnd += (pFMInfo->SectorSize >> 1) - 1;
  362.             }
  363.  
  364.             /* cope with special cases of random pointers: */
  365.             if ((lo & 3) == 2  &&  (hi & 3) == 2)
  366.                 if (pEnd == pStart)
  367.                     --pStart;
  368.                 else if (pStart > pEnd)
  369.                 {    ptr = pEnd;
  370.                     pEnd = pStart;
  371.                     pStart = ptr;
  372.                 }
  373.             DspNum(++tstnum, 1, 0, 3);
  374.  
  375.             /* "erase" whole chip: */
  376.             ptr = pScratch + (pFMInfo->TotalSize >> 1);
  377.             while (--ptr >= pScratch)
  378.                 *ptr = FM_ERASE_VAL;
  379.             if (!fm_write(pBase, pBase, pScratch,
  380.                     pFMInfo->TotalSize, 0))
  381.                 Err('E');
  382.  
  383.             /* change buffer values to detect accidental use: */
  384.             ptr = pScratch + (pFMInfo->TotalSize >> 1);
  385.             while (--ptr >= pScratch)
  386.                 *ptr = ~FM_ERASE_VAL;
  387.  
  388.             /* fill an area of RAM with a random value: */
  389.             randval = RND1(randval);
  390.             act = RND2(randval);
  391.             ptr = pScratch + (pEnd - pStart);
  392.             while (--ptr >= pScratch)
  393.                 *ptr = act;
  394.  
  395. #if 1            /* debug output, to help log errors: */
  396.             printf("%3d: %08x %08x\n", tstnum,
  397.                     pStart - pBase, pEnd - pBase);
  398. #elif 0            /* this can be gnuplotted with errorbars: */
  399.             printf("%3d %7d %7d %7d %08x %08x", tstnum, pStart - pBase,
  400.             pStart - pBase, pEnd - pBase, pStart - pBase, pEnd - pBase);
  401. #endif
  402.  
  403.             /* write the RAM area to flash: */
  404.             if (!fm_write(pBase, pStart, pScratch,
  405.                     (pEnd - pStart) << 1, pScr0))
  406.                 Err('W');
  407.  
  408.             /* verify any unwritten locations - after: */
  409.             exp = FM_ERASE_VAL;
  410.             ptr = pBase + ((pFMInfo->TotalSize >> 1) - 1);
  411.             while (ptr >= pEnd)
  412.             {    if (*ptr != exp)
  413.                 {    fm_error(ptr, exp, *ptr, 0xF2);
  414.                     Err('V');
  415.                 }
  416.                 --ptr;
  417.             }
  418.  
  419.             /* verify written locations: */
  420.             while (ptr >= pStart)
  421.             {    if (*ptr != act)
  422.                 {    fm_error(ptr, act, *ptr, 0xF3);
  423.                     Err('V');
  424.                 }
  425.                 --ptr;
  426.             }
  427.  
  428.             /* verify any unwritten locations - before: */
  429.             while (ptr >= pBase)
  430.             {    if (*ptr != exp)
  431.                 {    fm_error(ptr, exp, *ptr, 0xF4);
  432.                     Err('V');
  433.                 }
  434.                 --ptr;
  435.             }
  436.  
  437.             /* update error counter on display: */
  438.             if (fm_tot_errs)
  439.                 DspNum(fm_tot_errs, 1, 8,
  440.                     (fm_tot_errs <= 999 ? 3 : 4));
  441.         }
  442.     }
  443.  
  444.     /* all done: */
  445.     VBeep(50); Delay(50);
  446.     VBeep(50); Delay(50);
  447.     VBeep(50); Delay(50);
  448.     Delay(5000);
  449. }
  450.  
  451.  
  452. #endif
  453.  
  454.  
  455.  
  456. #if STANDALONE
  457.  
  458. static char VerStr[] = "FLASHTST Ver. 1D\n ";
  459.  
  460.     /* variables normally located in geint.s68: */
  461. long CTime = 0;
  462. long SeqNum = 0;
  463.  
  464.  
  465. main()        /* downloadable utility to perform flash chip tests */
  466. {
  467.     FMINFO FMInfo;
  468.  
  469. #if HUGE_TEST
  470.     /* provide a warning for this version: */
  471.     DspWrite("WARNING:  Huge\nflash mem test!!");
  472.     VBeep(1000);  Delay(4000);
  473. #endif
  474.  
  475.     /* say hello to the nice people: */
  476.     DspWrite(VerStr);
  477.     DspText("Flash mem. tests", 1, 0, 40);
  478. #if HUGE_TEST
  479.     DspText("*FMHUGE*", 0, 0, 8);
  480. #endif
  481.     VBeep(50); Delay(50); VBeep(50);
  482.  
  483.     /* init the output port: */
  484.     InitRS();
  485.  
  486.     /* reset chips; display size: */
  487.     fm_tot_errs = 0;
  488.     fm_intro((unsigned short *) FLASHBASE, &FMInfo, 'S', 5000);
  489.  
  490.     /* ensure that we have enough free ram to do these tests: */
  491. #if HUGE_TEST
  492.     if (FreeRAM + FMInfo.TotalSize > (char *) (RAMBASE + RAMSIZE))
  493. #else
  494.     if (FreeRAM + FMInfo.SectorSize > (char *) (RAMBASE + RAMSIZE))
  495. #endif
  496.     {    DspText("ERROR: RAM OVFL", 1, 0, 40);
  497.         while (1) { }
  498.     }
  499.  
  500.     /* do the test: */
  501. #if HUGE_TEST
  502.     fm_huge_test((unsigned short *) FLASHBASE, &FMInfo, (unsigned short *) FreeRAM);
  503. #else
  504.     fm_short_test((unsigned short *) FLASHBASE, &FMInfo, (unsigned short *) FreeRAM);
  505. #endif
  506.  
  507.     /* display final error total: */
  508.     DspWrite(VerStr);
  509.     DspText("# errors:", 1, 0, 40);
  510.     DspNum(fm_tot_errs, 1, 10, 6);
  511.     VBeep(50); Delay(50);
  512.     VBeep(50); Delay(50);
  513.     VBeep(50); Delay(50);
  514.  
  515.     /* hang forever: */
  516.     while (1) { }
  517. }
  518.  
  519. #endif
  520.